FrameLib  2.0
DSP processing with frames of arbitrary timing and length
FrameLib_Object.h
Go to the documentation of this file.
1 
2 #ifndef FRAMELIB_BLOCK_H
3 #define FRAMELIB_BLOCK_H
4 
5 #include "FrameLib_Types.h"
6 #include "FrameLib_Context.h"
7 #include "FrameLib_Parameters.h"
8 
9 #include <algorithm>
10 #include <string>
11 #include <sstream>
12 #include <iostream>
13 
28 template <class T>
30 {
31 
32 public:
33 
34  FrameLib_Queueable() : mNext(nullptr) {}
35 
46  class Queue
47  {
48  typedef void (T::*Method)(Queue *);
49 
50  public:
51 
52  Queue() : mFirst(nullptr), mTop(nullptr), mTail(nullptr) {}
53 
54  Queue(T *object, Method method) : mFirst(nullptr), mTop(nullptr), mTail(nullptr)
55  {
56  add(object);
57  start(method);
58  }
59 
60  // Non-copyable
61 
62  Queue(const Queue&) = delete;
63  Queue& operator=(const Queue&) = delete;
64 
65  void add(T *object)
66  {
67  // Do not add if nullptr or re-add if already in queue
68 
69  if (!object || object->FrameLib_Queueable<T>::mNext != nullptr)
70  return;
71 
72  // Add to the top /tail of the queue depending on whether the queue is open
73 
74  if (mTop)
75  {
76  mTail->FrameLib_Queueable<T>::mNext = object;
77  mTail = object;
78  }
79  else
80  mTop = mTail = object;
81  }
82 
83  void start(Method method)
84  {
85  assert(!mFirst && "Can't restart queue");
86 
87  mFirst = mTop;
88 
89  while (mTop)
90  {
91  T *object = mTop;
92  (object->*method)(this);
93  mTop = object->FrameLib_Queueable<T>::mNext;
94  object->FrameLib_Queueable<T>::mNext = nullptr;
95  }
96 
97  mFirst = mTail = nullptr;
98  }
99 
100  T *getFirst() const { return mFirst; }
101 
102  private:
103 
104  T *mFirst;
105  T *mTop;
106  T *mTail;
107  };
108 
109 private:
110 
111  T *mNext;
112 };
113 
114 
127 template <class T>
129 {
130 
131 public:
132 
134 
143  struct Connection
144  {
145  Connection() : mObject(nullptr), mIndex(0) {}
146  Connection(T *object, unsigned long index) : mObject(object), mIndex(index) {}
147 
148  friend bool operator == (const Connection& a, const Connection& b) { return a.mObject == b.mObject && a.mIndex == b.mIndex; }
149  friend bool operator != (const Connection& a, const Connection& b) { return !(a == b); }
150 
152  unsigned long mIndex;
153  };
154 
155 
156 private:
157 
158  // A connector is a thing with one input and many outputs
159 
160  struct Connector
161  {
162  Connector() : mInternal(false) {}
163 
164  void addOut(Connection connection, bool setInternal)
165  {
166  mInternal = setInternal ? true : mInternal;
167  addUniqueItem(mOut, connection);
168  }
169 
170  void deleteOut(Connection connection, bool setInternal)
171  {
172  deleteUniqueItem(mOut, connection);
173  mInternal = setInternal && !mOut.size() ? false : mInternal;
174  }
175 
176  void clearOuts(bool setInternal)
177  {
178  mOut.clear();
179  mInternal = setInternal ? false : mInternal;
180  }
181 
182  bool mInternal;
183  Connection mIn;
184  std::vector<Connection> mOut;
185  };
186 
187  // Connector method typedef and kOrdering definition
188 
189  typedef Connector& (FrameLib_Object::*ConnectorMethod)(unsigned long);
190 
191  const unsigned long kOrdering = -1;
192 
193 public:
194 
195  // Constructor / Destructor
196 
198  : mType(type), mContext(context), mAllocator(context), mProxy(proxy), mNumAudioChans(0), mSupportsOrderingConnections(false), mFeedback(false) {}
199 
200  virtual ~FrameLib_Object() { clearConnections(false); }
201 
202  // Object Type
203 
204  ObjectType getType() const { return mType; }
205 
206  // Context
207 
208  FrameLib_Context getContext() const { return mContext; }
209 
210  // Owner
211 
212  FrameLib_Proxy *getProxy() const { return mProxy; }
213 
214  // IO Queries
215 
216  unsigned long getNumIns() const { return mInputConnections.size(); }
217  unsigned long getNumOuts() const { return mOutputConnections.size(); }
218  unsigned long getNumAudioIns() const { return getType() != kOutput ? mNumAudioChans : 0; }
219  unsigned long getNumAudioOuts() const { return getType() == kOutput ? mNumAudioChans : 0; }
220  unsigned long getNumAudioChans() const { return mNumAudioChans; }
221 
222  // Set / Get Fixed Inputs
223 
224  virtual void setFixedInput(unsigned long idx, double *input, unsigned long size) = 0;
225  virtual const double *getFixedInput(unsigned long idx, unsigned long *size) = 0;
226 
227  // Audio Processing
228 
229  // Override to handle audio at the block level (reset called with the audio engine resets)
230 
231  virtual void blockUpdate(const double * const *ins, double **outs, unsigned long blockSize) = 0;
232  virtual void reset(double samplingRate, unsigned long maxBlockSize) = 0;
233 
234  // Return to host to request to be passed audio
235 
236  static bool handlesAudio() { return false; }
237 
238  // Info
239 
240  virtual std::string objectInfo(bool verbose = false) { return "No object info available"; }
241  virtual std::string inputInfo(unsigned long idx, bool verbose = false) { return "No input info available"; }
242  virtual std::string outputInfo(unsigned long idx, bool verbose = false) { return "No output info available"; }
243  virtual std::string audioInfo(unsigned long idx, bool verbose = false) { return "No audio channel info available"; }
244 
245  virtual FrameType inputType(unsigned long idx) const = 0;
246  virtual FrameType outputType(unsigned long idx) const = 0;
247 
248  // N.B. Parameter objects can be queried directly for info
249 
250  virtual const FrameLib_Parameters *getParameters() const { return nullptr; }
251 
252  // Connection
253 
254  ConnectionResult addConnection(Connection connection, unsigned long inIdx)
255  {
256  ConnectionResult result = connectionCheck(connection, false);
257  return (result == kConnectSuccess) ? changeConnection(connection, inIdx, true) : result;
258  }
259 
260  void deleteConnection(unsigned long inIdx)
261  {
262  changeConnection(Connection(), inIdx, true);
263  }
264 
266  {
267  ConnectionResult result = connectionCheck(connection, true);
268 
269  if (result == kConnectSuccess)
270  return addOrderingConnection(connection, true);
271 
272  return result;
273  }
274 
275  void deleteOrderingConnection(Connection connection)
276  {
277  deleteOrderingConnection(connection, true);
278  }
279 
281  {
282  clearOrderingConnections(true);
283  }
284 
286  {
287  clearConnections(true);
288  }
289 
290  // Aliasing
291 
292  ConnectionResult setInputAlias(Connection alias, unsigned long inIdx)
293  {
294  ConnectionResult result = connectionCheck(alias, false);
295 
296  if (result == kConnectSuccess)
297  {
298  changeConnection(Connection(), inIdx, false);
299  changeAlias(&FrameLib_Object::getInputConnector, alias, inIdx, true);
300  }
301 
302  return result;
303  }
304 
306  {
307  ConnectionResult result = connectionCheck(Connection(alias, 0), true);
308 
309  if (result == kConnectSuccess)
310  {
311  clearOrderingConnections(false);
312  changeOrderingAlias(alias, true);
313  }
314 
315  return result;
316  }
317 
318  ConnectionResult setOutputAlias(Connection alias, unsigned long outIdx)
319  {
320  ConnectionResult result = alias.mObject->connectionCheck(thisConnection(outIdx), false);
321 
322  if (result == kConnectSuccess)
323  {
324  clearOutput(outIdx);
325  if (alias.mObject)
326  alias.mObject->changeAlias(&FrameLib_Object::getOutputConnector, thisConnection(outIdx), alias.mIndex, true);
327  }
328 
329  return result;
330  }
331 
332  // Input Connection Queries
333 
334  bool isConnected(unsigned long inIdx) const { return getConnection(inIdx).mObject != nullptr; }
335  Connection getConnection(unsigned long inIdx) const { return getConnection(inIdx, false); }
336 
337  bool supportsOrderingConnections() const { return mSupportsOrderingConnections; }
338  unsigned long getNumOrderingConnections() const { return traverseOrderingAliases()->mOrderingConnections.size(); }
339  Connection getOrderingConnection(unsigned long idx) const { return getOrderingConnection(idx, false); }
340 
341  // Automatic Dependency Connections
342 
343  virtual void autoOrderingConnections() = 0;
344  virtual void clearAutoOrderingConnections() = 0;
345 
346  // Connection Update
347 
348  void callConnectionUpdate() { Queue queue(static_cast<T *>(this), &T::FrameLib_Object::connectionUpdate); }
349 
350  template <class U> void addOutputDependencies(std::vector<U *> &dependencies)
351  {
352  for (unsigned long i = 0; i < getNumOuts(); i++)
353  addOutputDependencies(dependencies, i);
354  }
355 
356  template <class U> void addOutputDependencies(std::vector<U *> &dependencies, unsigned long outIdx)
357  {
358  addOutputDependencies<std::vector<U *>>(dependencies, outIdx);
359  }
360 
361 protected:
362 
363  // IO Connection Queries (protected)
364 
365  Connection getConnectionInternal(unsigned long inIdx) const { return getConnection(inIdx, true); }
366  Connection getOrderingConnectionInternal(unsigned long idx) const { return getOrderingConnection(idx, true); }
367 
369  {
370  for (unsigned long i = 0; i < getNumOuts(); i++)
371  addOutputDependencies(queue, i);
372  }
373 
374  void addOutputDependencies(Queue *queue, unsigned long outIdx)
375  {
376  addOutputDependencies<Queue *>(queue, outIdx);
377  }
378 
379  // IO Setup
380 
381  void setIO(unsigned long nIns, unsigned long nOuts, unsigned long nAudioChans = 0)
382  {
383  mNumAudioChans = nAudioChans;
384 
385  mInputConnections.resize((getType() == kScheduler || nIns) ? nIns : 1);
386  mOutputConnections.resize(nOuts);
387  }
388 
389  // Ordering Setup
390 
391  void enableOrderingConnections() { mSupportsOrderingConnections = true; }
392 
393  // Memory Allocation
394 
395  template <class U> U *alloc(unsigned long N)
396  {
397  return reinterpret_cast<U *>(mAllocator->alloc(sizeof(U) * N));
398  }
399 
400  template <class U> void dealloc(U *& ptr)
401  {
402  mAllocator->dealloc(ptr);
403  ptr = nullptr;
404  }
405 
406  void clearAllocator() { mAllocator->clear(); }
407 
408  FrameLib_LocalAllocator::Storage *registerStorage(const char *name) { return mAllocator->registerStorage(name); }
409 
411  {
412  mAllocator->releaseStorage(storage->getName());
413  storage = nullptr;
414  }
415 
416  // Info Helpers
417 
418  static const char *formatInfo(const char *verboseStr, const char *briefStr, bool verbose)
419  {
420  return verbose ? verboseStr : briefStr;
421  }
422 
423  static std::string formatInfo(const char *str, unsigned long idx)
424  {
425  std::string info = str;
426  std::string idxStr = numberedString("", idx + 1);
427 
428  for (size_t pos = info.find("#", 0); pos != std::string::npos; pos = info.find("#", pos + 1))
429  info.replace(pos, 1, idxStr);
430 
431  return info;
432  }
433 
434  static std::string formatInfo(const char *verboseStr, const char *briefStr, unsigned long idx, bool verbose)
435  {
436  return formatInfo(formatInfo(verboseStr, briefStr, verbose), idx);
437  }
438 
439  static std::string formatInfo(const char *str, const char *replaceStr)
440  {
441  std::string info = str;
442 
443  for (size_t pos = info.find("#", 0); pos != std::string::npos; pos = info.find("#", pos + 1))
444  info.replace(pos, 1, replaceStr);
445 
446  return info;
447  }
448 
449  static std::string formatInfo(const char *verboseStr, const char *briefStr, const char *replaceStr, bool verbose)
450  {
451  return formatInfo(formatInfo(verboseStr, briefStr, verbose), replaceStr);
452  }
453 
454  static std::string parameterInputInfo(bool verbose)
455  {
456  return formatInfo("Parameter Update - tagged input updates parameters", "Parameter Update", verbose);
457  }
458 
459  // String With Number Helper
460 
461  static std::string numberedString(const char *str, unsigned long idx)
462  {
463  std::ostringstream outStr;
464 
465  outStr << str;
466  outStr << idx;
467 
468  return outStr.str();
469  }
470 
471  // Unique List Helpers
472 
473  template <class U> static bool addUniqueItem(std::vector<U>& list, U item)
474  {
475  if (std::find(list.begin(), list.end(), item) != list.end())
476  return false;
477 
478  list.push_back(item);
479  return true;
480  }
481 
482  template <class U> static bool deleteUniqueItem(std::vector<U>& list, U item)
483  {
484  auto it = std::find(list.begin(), list.end(), item);
485 
486  if (it == list.end())
487  return false;
488 
489  list.erase(it);
490  return true;
491  }
492 
493  // Input getter helper for empty inputs
494 
495  const double *getEmptyFixedInput(unsigned long idx, unsigned long *size)
496  {
497  *size = 0;
498  return nullptr;
499  }
500 
501 private:
502 
503  // Connection Methods (private)
504 
505  Connector& getInputConnector(unsigned long idx) { return mInputConnections[idx]; }
506  Connector& getOutputConnector(unsigned long idx) { return mOutputConnections[idx]; }
507  Connector& getOrderingConnector(unsigned long idx) { return mOrderingConnector; }
508 
509  static bool isOutput(ConnectorMethod method) { return method == &FrameLib_Object::getOutputConnector; }
510 
511  Connection thisConnection(unsigned long idx) const { return Connection(static_cast<T *>(const_cast<FrameLib_Object *>(this)), idx); }
512 
513  // Add to / Delete from a Connector's Output List
514 
515  void addToConnector(ConnectorMethod method, Connection connection, unsigned long idx, bool setInternal = false)
516  {
517  if (connection.mObject)
518  (connection.mObject->*method)(connection.mIndex).addOut(thisConnection(idx), setInternal);
519  }
520 
521  void deleteFromConnector(ConnectorMethod method, Connection connection, unsigned long idx, bool setInternal = false)
522  {
523  if (connection.mObject)
524  (connection.mObject->*method)(connection.mIndex).deleteOut(thisConnection(idx), setInternal);
525  }
526 
527  // Queue the Dependencies of a Vector of Connectors
528 
529  void queueConnectorVectorDependencies(Queue *queue, const std::vector<Connector>& connectors) const
530  {
531  for (auto it = connectors.begin(); it != connectors.end(); it++)
532  for (auto jt = it->mOut.begin(); jt != it->mOut.end(); jt++)
533  queue->add(jt->mObject);
534  }
535 
536  // Default Connection Update
537 
538  virtual void connectionUpdate(Queue *queue)
539  {
540  queueConnectorVectorDependencies(queue, mInputConnections);
541 
542  for (auto it = mOutputConnections.begin(); it != mOutputConnections.end(); it++)
543  queue->add(it->mIn.mObject);
544  };
545 
546  // Input Connection Queries (with and without alias resolution)
547 
548  Connection getConnection(unsigned long inIdx, bool resolveAliases) const
549  {
550  Connection connection = traverseAliases(&FrameLib_Object::getInputConnector, inIdx);
551  connection = connection.mObject->mInputConnections[connection.mIndex].mIn;
552  if (resolveAliases && connection.mObject)
553  connection = connection.mObject->traverseAliases(&FrameLib_Object::getOutputConnector, connection.mIndex);
554  return connection;
555  }
556 
557  Connection getOrderingConnection(unsigned long idx, bool resolveAliases) const
558  {
559  Connection connection = traverseOrderingAliases()->mOrderingConnections[idx];
560  if (resolveAliases && connection.mObject)
561  connection = connection.mObject->traverseAliases(&FrameLib_Object::getOutputConnector, connection.mIndex);
562  return connection;
563  }
564 
565  // Connection Check
566 
567  ConnectionResult connectionCheck(Connection connection, bool ordering)
568  {
569  if (ordering && !supportsOrderingConnections())
571 
572  if (connection.mObject == this)
573  return kConnectSelfConnection;
574 
575  if (connection.mObject->mContext != mContext)
576  return kConnectWrongContext;
577 
578  if (detectFeedback(connection.mObject))
580 
581  return kConnectSuccess;
582  }
583 
584  // Notifications
585 
586  void notifySelf(bool notify, Queue *queue = nullptr)
587  {
588  if (notify)
589  {
590  if (queue)
591  queue->add(dynamic_cast<T *>(const_cast<FrameLib_Object *>(this)));
592  else
593  callConnectionUpdate();
594  }
595  }
596 
597  void notifyConnectionsChanged(Connection connection, Queue *queue = nullptr)
598  {
599  if (connection.mObject)
600  {
601  if (queue)
602  queue->add(connection.mObject);
603  else
604  connection.mObject->callConnectionUpdate();
605  }
606  }
607 
608  void notifyAliasChanged(ConnectorMethod method, Connection connection, Queue *queue)
609  {
610  if (!connection.mObject)
611  return;
612 
613  if (method == &FrameLib_Object::getOrderingConnector)
614  {
615  FrameLib_Object *object = connection.mObject->traverseOrderingAliases();
616  std::vector<Connection> &connections = object->mOrderingConnections;
617 
618  for (auto it = connections.begin(); it != connections.end(); it++)
619  notifyConnectionsChanged(*it, queue);
620  }
621  else
622  {
623  connection = connection.mObject->traverseAliases(method, connection.mIndex);
624  notifyConnectionsChanged((connection.mObject->*method)(connection.mIndex).mIn, queue);
625  }
626  }
627 
628  // Change Input Connection
629 
630  ConnectionResult changeConnection(Connection connection, unsigned long inIdx, bool notify, Queue *queue = nullptr)
631  {
632  if (mInputConnections[inIdx].mIn == connection)
633  return kConnectSuccess;
634 
635  if (mInputConnections[inIdx].mInternal || (connection.mObject && connection.mObject->mOutputConnections[connection.mIndex].mInternal))
636  return kConnectAliased;
637 
638  // Update all values (note the swap)
639 
640  std::swap(mInputConnections[inIdx].mIn, connection);
641  deleteFromConnector(&FrameLib_Object::getOutputConnector, connection, inIdx);
642  addToConnector(&FrameLib_Object::getOutputConnector, mInputConnections[inIdx].mIn, inIdx);
643 
644  // Notify of updates
645 
646  notifyConnectionsChanged(connection, queue);
647  notifyConnectionsChanged(mInputConnections[inIdx].mIn, queue);
648  notifySelf(notify, queue);
649 
650  return kConnectSuccess;
651  }
652 
653  // Change Ordering Connection
654 
655  typedef bool ListMethod(std::vector<Connection>&, Connection);
656  typedef void (FrameLib_Object::*AlterMethod)(ConnectorMethod, Connection, unsigned long, bool);
657 
658  ConnectionResult changeOrderingConnection(Connection connection, ListMethod listUpdate, AlterMethod alterConnector, bool notify, Queue *queue)
659  {
660  if (!supportsOrderingConnections())
662 
663  if (mOrderingConnector.mInternal || connection.mObject->mOutputConnections[connection.mIndex].mInternal)
664  return kConnectAliased;
665 
666  // Add / Delete and update all values
667 
668  if (!listUpdate(mOrderingConnections, connection))
669  return kConnectSuccess;
670 
671  (this->*alterConnector)(&FrameLib_Object::getOutputConnector, connection, kOrdering, false);
672 
673  // Notify (use queue to minimise calls, and ensure all changes are already complete)
674 
675  notifyConnectionsChanged(connection, queue);
676  notifySelf(notify, queue);
677 
678  return kConnectSuccess;
679  }
680 
681  ConnectionResult addOrderingConnection(Connection connection, bool notify, Queue *queue = nullptr)
682  {
683  return changeOrderingConnection(connection, &addUniqueItem<Connection>, &FrameLib_Object::addToConnector, notify, queue);
684  }
685 
686  void deleteOrderingConnection(Connection connection, bool notify, Queue *queue = nullptr)
687  {
688  changeOrderingConnection(connection, &deleteUniqueItem<Connection>, &FrameLib_Object::deleteFromConnector, notify, queue);
689  }
690 
691  // Clear Ordering Connections
692 
693  void clearOrderingConnections(bool notify, Queue *queue = nullptr)
694  {
695  if (!supportsOrderingConnections() || mOrderingConnector.mInternal)
696  return;
697 
698  while (mOrderingConnections.size())
699  {
700  // Update all values
701 
702  Connection connection = mOrderingConnections.back();
703  mOrderingConnections.pop_back();
704  deleteFromConnector(&FrameLib_Object::getOutputConnector, connection, kOrdering);
705 
706  // Notify
707 
708  notifyConnectionsChanged(connection, queue);
709  }
710 
711  // Notify
712 
713  notifySelf(notify, queue);
714  }
715 
716  // Clear output
717 
718  void clearOutput(unsigned long outIdx, Queue *queue = nullptr)
719  {
720  while (!mOutputConnections[outIdx].mInternal && mOutputConnections[outIdx].mOut.size())
721  {
722  // Update all values
723 
724  Connection connection = mOutputConnections[outIdx].mOut.back();
725  mOutputConnections[outIdx].mOut.pop_back();
726 
727  if (connection.mIndex == kOrdering)
728  connection.mObject->deleteOrderingConnection(thisConnection(outIdx), false, queue);
729  else
730  connection.mObject->mInputConnections[connection.mIndex].mIn = Connection();
731 
732  // Notify
733 
734  notifyConnectionsChanged(connection, queue);
735  }
736  }
737 
738  // Clear All Connections
739 
740  void clearConnections(bool notify)
741  {
742  // Clear input connections
743 
744  Queue queue;
745 
746  for (unsigned long i = 0; i < getNumIns(); i++)
747  {
748  changeConnection(Connection(), i, false, &queue);
749  changeAlias(&FrameLib_Object::getInputConnector, Connection(), i, false, &queue);
750  clearAliases(&FrameLib_Object::getInputConnector, i, &queue);
751  }
752 
753  // Clear ordering connections
754 
755  clearOrderingConnections(false, &queue);
756  changeOrderingAlias(nullptr, false, &queue);
757  clearAliases(&FrameLib_Object::getOrderingConnector, kOrdering, &queue);
758 
759  // Clear outputs
760 
761  for (unsigned long i = 0; i < getNumOuts(); i++)
762  {
763  clearOutput(i, &queue);
764  changeAlias(&FrameLib_Object::getOutputConnector, Connection(), i, false, &queue);
765  clearAliases(&FrameLib_Object::getOutputConnector, i, &queue);
766  }
767 
768  // Notify
769 
770  notifySelf(notify, &queue);
771 
772  queue.start(&T::FrameLib_Object::connectionUpdate);
773  }
774 
775  // Add Output Dependencies
776 
777  void addDependency(Queue *queue) const
778  {
779  queue->add(dynamic_cast<T *>(const_cast<FrameLib_Object *>(this)));
780  }
781 
782  template <class U> void addDependency(std::vector<U *>& dependencies) const
783  {
784  U *object = dynamic_cast<U *>(const_cast<FrameLib_Object *>(this));
785 
786  if (object)
787  addUniqueItem(dependencies, object);
788  }
789 
790  template <class U>
791  void traverseDependencies(U& dependencies, const Connector& connector, void (FrameLib_Object::*method)(U&, unsigned long) const) const
792  {
793  for (auto it = connector.mOut.begin(); it != connector.mOut.end(); it++)
794  (it->mObject->*method)(dependencies, it->mIndex);
795  }
796 
797  template <class U> void addOutputDependencies(U &dependencies, unsigned long outIdx) const
798  {
799  if (mOutputConnections[outIdx].mInternal)
800  traverseDependencies(dependencies, mOutputConnections[outIdx], &FrameLib_Object::addOutputDependencies<U>);
801  else
802  traverseDependencies(dependencies, mOutputConnections[outIdx], &FrameLib_Object::unwrapInputAliases<U>);
803  }
804 
805  template <class U> void unwrapInputAliases(U& dependencies, unsigned long inIdx) const
806  {
807  if (inIdx == kOrdering && mOrderingConnector.mOut.size())
808  traverseDependencies(dependencies, mOrderingConnector, &FrameLib_Object::unwrapInputAliases<U>);
809  else if (inIdx != kOrdering && mInputConnections[inIdx].mOut.size())
810  traverseDependencies(dependencies, mInputConnections[inIdx], &FrameLib_Object::unwrapInputAliases<U>);
811  else
812  addDependency(dependencies);
813  }
814 
815  // Aliasing Methods
816 
817  Connection traverseAliases(ConnectorMethod method, unsigned long idx) const
818  {
819  const Connector& connector = (const_cast<FrameLib_Object *>(this)->*method)(idx);
820 
821  if ((!isOutput(method) && connector.mInternal) || (isOutput(method) && connector.mIn.mObject))
822  return connector.mIn.mObject->traverseAliases(method, connector.mIn.mIndex);
823 
824  return thisConnection(idx);
825  }
826 
827  void changeAlias(ConnectorMethod method, Connection alias, unsigned long idx, bool notify, Queue *queue = nullptr)
828  {
829  Connector& connector = (this->*method)(idx);
830 
831  if (connector.mIn.mObject && !isOutput(method) && !connector.mInternal)
832  return;
833 
834  // Update all values (note the swap)
835 
836  std::swap(connector.mIn, alias);
837  connector.mInternal = isOutput(method) ? connector.mInternal : (bool) connector.mIn.mObject;
838  deleteFromConnector(method, alias, idx, isOutput(method));
839  addToConnector(method, connector.mIn, idx, isOutput(method));
840 
841  // Notify of updates
842 
843  notifyAliasChanged(method, alias, queue);
844  notifyAliasChanged(method, connector.mIn, queue);
845  notifySelf(notify, queue);
846  }
847 
848  void clearAliases(ConnectorMethod method, unsigned long idx, Queue *queue)
849  {
850  // N.B. Queue pointer allows the pointer to be passed by reference (as required for the vector versions)
851 
852  Connector& connector = (this->*method)(idx);
853 
854  if (isOutput(method) && !connector.mInternal)
855  return;
856 
857  // Create a list of dependencies
858 
859  if (isOutput(method))
860  addOutputDependencies(queue, idx);
861  else
862  unwrapInputAliases(queue, idx);
863 
864  // Remove from aliased objects and clear
865 
866  for (auto it = connector.mOut.begin(); it != connector.mOut.end(); it++)
867  (it->mObject->*method)(it->mIndex).mIn = Connection();
868  connector.clearOuts(isOutput(method));
869  }
870 
871  // Simpler Ordering Calls
872 
873  FrameLib_Object *traverseOrderingAliases() const { return traverseAliases(&FrameLib_Object::getOrderingConnector, kOrdering).mObject; }
874 
875  void changeOrderingAlias(T *alias, bool notify, Queue *queue = nullptr)
876  {
877  changeAlias(&FrameLib_Object::getOrderingConnector, Connection(alias, kOrdering), kOrdering, notify, queue);
878  }
879 
880  // Detect Potential Feedback in a Network
881 
882  bool detectFeedback(T *object)
883  {
884  object->mFeedback = false;
885  Queue queue(static_cast<T*>(this), &T::feedbackProbe);
886  return object->mFeedback;
887  }
888 
889  void feedbackProbe(Queue *queue)
890  {
891  mFeedback = true;
892  queueConnectorVectorDependencies(queue, mOutputConnections);
893  }
894 
895  // Data
896 
897  const ObjectType mType;
898  FrameLib_Context mContext;
899  FrameLib_Context::Allocator mAllocator;
900 
901  FrameLib_Proxy *mProxy;
902 
903  // Audio IO Counts
904 
905  unsigned long mNumAudioChans;
906 
907  // Connections
908 
909  std::vector<Connector> mInputConnections;
910  std::vector<Connector> mOutputConnections;
911  std::vector<Connection> mOrderingConnections;
912  Connector mOrderingConnector;
913 
914  bool mSupportsOrderingConnections;
915  bool mFeedback;
916 };
917 
918 
931 class FrameLib_Block : public FrameLib_Object<FrameLib_Block>
932 {
933 
934 public:
935 
936  // Constructor / Destructor
937 
938  FrameLib_Block(ObjectType type, FrameLib_Context context, FrameLib_Proxy *proxy) : FrameLib_Object<FrameLib_Block>(type, context, proxy) {}
939  virtual ~FrameLib_Block() {}
940 
941  // Stream Awareness
942 
943  virtual void setStream(void *streamOwner, unsigned long stream) {}
944 };
945 
946 #endif
ObjectType
Definition: FrameLib_Types.h:53
holds the connected object and IO indices for a connection to an object
Definition: FrameLib_Object.h:143
bool isConnected(unsigned long inIdx) const
Definition: FrameLib_Object.h:334
virtual std::string objectInfo(bool verbose=false)
Definition: FrameLib_Object.h:240
void deleteConnection(unsigned long inIdx)
Definition: FrameLib_Object.h:260
virtual const FrameLib_Parameters * getParameters() const
Definition: FrameLib_Object.h:250
ConnectionResult addOrderingConnection(Connection connection)
Definition: FrameLib_Object.h:265
unsigned long mIndex
Definition: FrameLib_Object.h:152
Queue(T *object, Method method)
Definition: FrameLib_Object.h:54
unsigned long getNumOuts() const
Definition: FrameLib_Object.h:217
a set of parameters for a FrameLib object.
Definition: FrameLib_Parameters.h:30
void addOutputDependencies(std::vector< U *> &dependencies)
Definition: FrameLib_Object.h:350
FrameLib_Proxy * getProxy() const
Definition: FrameLib_Object.h:212
Connection getConnectionInternal(unsigned long inIdx) const
Definition: FrameLib_Object.h:365
virtual ~FrameLib_Block()
Definition: FrameLib_Object.h:939
a class used to represent distinct non-connectable areas in the host environment. ...
Definition: FrameLib_Context.h:21
void deleteOrderingConnection(Connection connection)
Definition: FrameLib_Object.h:275
static std::string formatInfo(const char *str, unsigned long idx)
Definition: FrameLib_Object.h:423
static bool addUniqueItem(std::vector< U > &list, U item)
Definition: FrameLib_Object.h:473
void dealloc(U *&ptr)
Definition: FrameLib_Object.h:400
Definition: FrameLib_Types.h:56
Definition: FrameLib_Types.h:56
ManagedPointer< FrameLib_LocalAllocator, &Global::getAllocator, &Global::releaseAllocator > Allocator
Definition: FrameLib_Context.h:103
FrameLib_LocalAllocator::Storage * registerStorage(const char *name)
Definition: FrameLib_Object.h:408
unsigned long getNumAudioChans() const
Definition: FrameLib_Object.h:220
a virtual struct allowing for extensible communication to/from the host environment.
Definition: FrameLib_Types.h:69
virtual std::string outputInfo(unsigned long idx, bool verbose=false)
Definition: FrameLib_Object.h:242
Queue & operator=(const Queue &)=delete
void addOutputDependencies(Queue *queue, unsigned long outIdx)
Definition: FrameLib_Object.h:374
a template class for items that can be placed on a queue
Definition: FrameLib_Object.h:29
T * getFirst() const
Definition: FrameLib_Object.h:100
ConnectionResult setOutputAlias(Connection alias, unsigned long outIdx)
Definition: FrameLib_Object.h:318
static std::string formatInfo(const char *verboseStr, const char *briefStr, const char *replaceStr, bool verbose)
Definition: FrameLib_Object.h:449
ObjectType getType() const
Definition: FrameLib_Object.h:204
Queue()
Definition: FrameLib_Object.h:52
const char * getName() const
Definition: FrameLib_Memory.h:328
an abstract template class providing an interface for FrameLib objects and implementing connectivity ...
Definition: FrameLib_Object.h:128
void clearConnections()
Definition: FrameLib_Object.h:285
static std::string parameterInputInfo(bool verbose)
Definition: FrameLib_Object.h:454
Definition: FrameLib_Types.h:56
ConnectionResult setInputAlias(Connection alias, unsigned long inIdx)
Definition: FrameLib_Object.h:292
virtual void setStream(void *streamOwner, unsigned long stream)
Definition: FrameLib_Object.h:943
ConnectionResult addConnection(Connection connection, unsigned long inIdx)
Definition: FrameLib_Object.h:254
Definition: FrameLib_Types.h:56
void clearAllocator()
Definition: FrameLib_Object.h:406
const double * getEmptyFixedInput(unsigned long idx, unsigned long *size)
Definition: FrameLib_Object.h:495
virtual std::string inputInfo(unsigned long idx, bool verbose=false)
Definition: FrameLib_Object.h:241
Connection getOrderingConnection(unsigned long idx) const
Definition: FrameLib_Object.h:339
FrameLib_Context getContext() const
Definition: FrameLib_Object.h:208
void clearOrderingConnections()
Definition: FrameLib_Object.h:280
bool supportsOrderingConnections() const
Definition: FrameLib_Object.h:337
an abstract class that represents either a single FrameLib_DSP object, or a group of connected FrameL...
Definition: FrameLib_Object.h:931
size_t blockSize(void *ptr)
Definition: FrameLib_Memory.cpp:23
Connection getOrderingConnectionInternal(unsigned long idx) const
Definition: FrameLib_Object.h:366
ConnectionResult setOrderingAlias(T *alias)
Definition: FrameLib_Object.h:305
void addOutputDependencies(std::vector< U *> &dependencies, unsigned long outIdx)
Definition: FrameLib_Object.h:356
void enableOrderingConnections()
Definition: FrameLib_Object.h:391
T * mObject
Definition: FrameLib_Object.h:151
static bool handlesAudio()
Definition: FrameLib_Object.h:236
U * alloc(unsigned long N)
Definition: FrameLib_Object.h:395
static std::string formatInfo(const char *str, const char *replaceStr)
Definition: FrameLib_Object.h:439
static bool deleteUniqueItem(std::vector< U > &list, U item)
Definition: FrameLib_Object.h:482
FrameLib_Queueable()
Definition: FrameLib_Object.h:34
FrameLib_Block(ObjectType type, FrameLib_Context context, FrameLib_Proxy *proxy)
Definition: FrameLib_Object.h:938
unsigned long getNumOrderingConnections() const
Definition: FrameLib_Object.h:338
virtual std::string audioInfo(unsigned long idx, bool verbose=false)
Definition: FrameLib_Object.h:243
void setIO(unsigned long nIns, unsigned long nOuts, unsigned long nAudioChans=0)
Definition: FrameLib_Object.h:381
virtual ~FrameLib_Object()
Definition: FrameLib_Object.h:200
void add(T *object)
Definition: FrameLib_Object.h:65
static std::string formatInfo(const char *verboseStr, const char *briefStr, unsigned long idx, bool verbose)
Definition: FrameLib_Object.h:434
void addOutputDependencies(Queue *queue)
Definition: FrameLib_Object.h:368
a single-threaded queue for non-recursive queuing of items for processing
Definition: FrameLib_Object.h:46
Connection()
Definition: FrameLib_Object.h:145
void releaseStorage(FrameLib_LocalAllocator::Storage *&storage)
Definition: FrameLib_Object.h:410
unsigned long getNumAudioOuts() const
Definition: FrameLib_Object.h:219
unsigned long getNumAudioIns() const
Definition: FrameLib_Object.h:218
Definition: FrameLib_Types.h:53
ConnectionResult
Definition: FrameLib_Types.h:56
FrameType
Definition: FrameLib_Types.h:54
static const char * formatInfo(const char *verboseStr, const char *briefStr, bool verbose)
Definition: FrameLib_Object.h:418
Connection(T *object, unsigned long index)
Definition: FrameLib_Object.h:146
named storage local to a specific context.
Definition: FrameLib_Memory.h:278
Connection getConnection(unsigned long inIdx) const
Definition: FrameLib_Object.h:335
Definition: FrameLib_Types.h:53
void start(Method method)
Definition: FrameLib_Object.h:83
typename FrameLib_Queueable< FrameLib_Multistream >::Queue Queue
Definition: FrameLib_Object.h:133
unsigned long getNumIns() const
Definition: FrameLib_Object.h:216
FrameLib_Object(ObjectType type, FrameLib_Context context, FrameLib_Proxy *proxy)
Definition: FrameLib_Object.h:197
static std::string numberedString(const char *str, unsigned long idx)
Definition: FrameLib_Object.h:461
void callConnectionUpdate()
Definition: FrameLib_Object.h:348
Definition: FrameLib_Types.h:56
Definition: FrameLib_Types.h:56